﻿namespace BeepMaker
{
    using System.Windows.Forms;
    using System;
    using System.Drawing;
    using System.Diagnostics;
    using System.Threading;
    using System.Configuration;
    using System.Reflection;
    using System.IO;

    public class MainForm : Form
    {
        [STAThread]
        public static void Main(string[] args)
        {
            if (args.Length == 1 && args[0] == "INSTALLER")
            {
                Process.Start(Application.ExecutablePath); //Don't use Application.Restart(), as it passes the same arg in
                return;
            }
            Application.Run(new MainForm());
        }

        private NotifyIcon trayIcon;
        private ContextMenu trayMenu;

        private System.Threading.Timer intervalTimer;

        private int frequency;
        private int duration;
        private int amplitude;
        private int interval;

        private bool isWorking;

        private Icon redIcon;
        private Icon greenIcon;

        private string configFilePath;

        private MenuItem startMenuItem;
        private MenuItem stopMenuItem;

        private MenuItem playNowMenuItem;

        public MainForm()
        {
            Thread.Sleep(2000); //to give the user the "feeling" of the restart

            configFilePath = Assembly.GetExecutingAssembly().Location;
            string currentPath = configFilePath.Remove(configFilePath.LastIndexOf('\\'));
            configFilePath += ".config";

            redIcon = new Icon(Path.Combine(currentPath, "red.ico"), 40, 40);
            greenIcon = new Icon(Path.Combine(currentPath, "green.ico"), 40, 40);

            trayMenu = new ContextMenu();

            startMenuItem = new MenuItem("Start", OnStart);
            stopMenuItem = new MenuItem("Stop", OnStop);

            playNowMenuItem = new MenuItem("Play Now", OnPlayNow);

            trayMenu.MenuItems.Add(startMenuItem);
            trayMenu.MenuItems.Add(stopMenuItem);
            trayMenu.MenuItems.Add("-");
            trayMenu.MenuItems.Add(playNowMenuItem);
            trayMenu.MenuItems.Add("-");
            trayMenu.MenuItems.Add("Edit Config", OnEditConfig);
            trayMenu.MenuItems.Add("-");
            trayMenu.MenuItems.Add("Exit", OnExit);

            trayIcon = new NotifyIcon();
            trayIcon.Text = "Periodic Beeper";

            trayIcon.ContextMenu = trayMenu;
            trayIcon.Visible = true;
        }

        private void OnPlayNow(object sender, EventArgs e)
        {
            string oldText = playNowMenuItem.Text;
            playNowMenuItem.Text = "Playing...";
            playNowMenuItem.Enabled = false;
            InterruptExecutionAndDoSomething(
                () =>
                {
                    Beeper.Singleton.Beep();
                }, false,
                (o) =>
                {
                    playNowMenuItem.Enabled = true;
                    playNowMenuItem.Text = oldText;
                }
            );
        }

        private  void OnStart(object sender, EventArgs e)
        {
            startMenuItem.Enabled = false;
            intervalTimer.Change(interval, interval);
            trayIcon.Icon = greenIcon;
            isWorking = true;
            stopMenuItem.Enabled = true;
        }

        private  void OnStop(object sender, EventArgs e)
        {
            stopMenuItem.Enabled = false;
            intervalTimer.Change(Timeout.Infinite, Timeout.Infinite);
            trayIcon.Icon = redIcon;
            isWorking = false;
            startMenuItem.Enabled = true;
        }

        protected override void OnLoad(EventArgs e)
        {
            Visible = false; // Hide form window.
            ShowInTaskbar = false; // Remove from taskbar.

            AppSettingsReader appSetReader = new System.Configuration.AppSettingsReader();
            amplitude = (int)appSetReader.GetValue("amplitude", typeof(int));
            amplitude = Math.Min(Math.Max(Consts.MIN_AMPLITUDE, amplitude), Consts.MAX_AMPLITUDE);

            frequency = (int)appSetReader.GetValue("frequencyInHertz", typeof(int));
            frequency = Math.Min(Math.Max(Consts.MIN_FREQUENCY_IN_HERTZ, frequency), Consts.MAX_FREQUENCY_IN_HERTZ);

            duration = (int)appSetReader.GetValue("durationInMilliSeconds", typeof(int));
            duration = Math.Min(Math.Max(Consts.MIN_DURATION_IN_MILLISECONDS, duration), Consts.MAX_DURATION_IN_MILLISECONDS);

            interval = (int)appSetReader.GetValue("intervalInMilliSeconds", typeof(int));
            interval = Math.Min(Math.Max(Consts.MIN_INTERVAL_IN_MILLISECONDS, interval), Consts.MAX_INTERVAL_IN_MILLISECONDS);

            Beeper.Singleton.Amplitude = amplitude;
            Beeper.Singleton.Duration = duration;
            Beeper.Singleton.Frequency = frequency;

            //starts as "red"
            intervalTimer = new System.Threading.Timer((o) =>
                {
                    Beeper.Singleton.Beep();
                    //Beeper.Beep(amplitude, frequency, duration);
                }, null, Timeout.Infinite, Timeout.Infinite
                );
            OnStop(this, new EventArgs());

            base.OnLoad(e);
        }

        private void OnEditConfig(object sender, EventArgs e)
        {
            //old way Process.Start(new ProcessStartInfo("notepad.exe", configFilePath));
            InterruptExecutionAndDoSomething(
                (() => new Config().ShowDialog())
                , false
                , null
            );
        }

        private delegate void Action();
        private void InterruptExecutionAndDoSomething(Action toDo, bool disableContextMenu, AsyncCallback callback)
        {
            bool oldStartMenuItemEnabled = startMenuItem.Enabled;
            bool oldStopMenuItemEnabled = stopMenuItem.Enabled;

            bool wasWorking = isWorking;            
            ContextMenu oldMenu = null;
            if (disableContextMenu)
            {
                oldMenu = trayIcon.ContextMenu;
                trayIcon.ContextMenu = null;
            }
            if (isWorking)
                OnStop(this, null);
            startMenuItem.Enabled = stopMenuItem.Enabled = false;
            if (callback != null)
                toDo.BeginInvoke((o) =>
                    {
                        callback.Invoke(o);
                        if (wasWorking)
                            OnStart(this, null);
                        if (disableContextMenu)
                            trayIcon.ContextMenu = oldMenu;

                        startMenuItem.Enabled = oldStartMenuItemEnabled;
                        stopMenuItem.Enabled = oldStopMenuItemEnabled;
                    }, null);
            else
            {
                toDo.Invoke();
                if (wasWorking)
                    OnStart(this, null);
                if (disableContextMenu)
                    trayIcon.ContextMenu = oldMenu;

                startMenuItem.Enabled = oldStartMenuItemEnabled;
                stopMenuItem.Enabled = oldStopMenuItemEnabled;
            }

        }

        private void OnExit(object sender, EventArgs e)
        {
            Application.Exit();
        }

        protected override void Dispose(bool isDisposing)
        {
            if (isDisposing)
            {
                // Release the icon resource.
                if (intervalTimer != null)
                    intervalTimer.Dispose();
                trayIcon.Dispose();
            }

            base.Dispose(isDisposing);
        }
    }
}